;================================================================
;  text.s
;               Text mode display
;
;================================================================
;
; 25thanni, a demo dedicated to the 25th anniversary of the ZX81.
;
; (c)2006 Bodo Wenzel
;
; This program is free software; you can redistribute it and/or
; modify it under the terms of the GNU General Public License as
; published by the Free Software Foundation; either version 2 of
; the License, or (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public
; License along with this program; if not, write to the Free
; Software Foundation Inc., 59 Temple Place, Suite 330, Boston,
; MA 02111-1307 USA
;================================================================

	.module	text

;= Externals ====================================================

	.globl	i_reg
	.globl	text_file

	.globl	M_TOP
	.globl	M_BOTTOM
	.globl	vsync

	.globl	DELAY_OFFSET
	.globl	delay

;= Constants ====================================================

ZX_FONT_I_REG	==	0x1E
GREY_I_REG	==	0x0E

TEXT_ROWS	==	24
TEXT_COLUMNS	==	32
CHAR_WIDTH	==	8
CHAR_HEIGHT	==	8

CHAR_MASK	==	0x3F

	; The graphic defines are build from the hex value:
	; +-------+-------+
	; | bit 0 | bit 1 |
	; +-------+-------+
	; | bit 2 | bit 3 |
	; +-------+-------+
G0	==	0x00		; graphic none
G1	==	0x01		; graphic upper left
G2	==	0x02		; graphic upper right
G3	==	0x03		; graphic upper both
G4	==	0x04		; graphic lower left
G5	==	0x05		; graphic both left
G6	==	0x06		; graphic lower left, upper right
G7	==	0x07		; graphic all but lower right
G8	==	0x87		; graphic lower right
G9	==	0x86		; graphic lower right, upper left
GA	==	0x85		; graphic both right
GB	==	0x84		; graphic all but lower left
GC	==	0x83		; graphic lower both
GD	==	0x82		; graphic all but upper right
GE	==	0x81		; graphic all but upper left
GF	==	0x80		; graphic all

__	==	0x00		; space
X8	==	0x08		; graphic grey
X9	==	0x09		; graphic lower grey
XA	==	0x0A		; graphic upper grey
QU	==	0x0B		; quote
PD	==	0x0C		; pound
DL	==	0x0D		; dollar
CL	==	0x0E		; colon
QM	==	0x0F		; question mark
LP	==	0x10		; left parenthesis
RP	==	0x11		; right parenthesis
GT	==	0x12		; greater than
LT	==	0x13		; less than
EQ	==	0x14		; equal
PL	==	0x15		; plus
MI	==	0x16		; minus
TI	==	0x17		; times (star)
SL	==	0x18		; slash
SC	==	0x19		; semicolon
CM	==	0x1A		; comma
PE	==	0x1B		; period
_0	==	0x1C
_1	==	0x1D
_2	==	0x1E
_3	==	0x1F
_4	==	0x20
_5	==	0x21
_6	==	0x22
_7	==	0x23
_8	==	0x24
_9	==	0x25
_A	==	0x26
_B	==	0x27
_C	==	0x28
_D	==	0x29
_E	==	0x2A
_F	==	0x2B
_G	==	0x2C
_H	==	0x2D
_I	==	0x2E
_J	==	0x2F
_K	==	0x30
_L	==	0x31
_M	==	0x32
_N	==	0x33
_O	==	0x34
_P	==	0x35
_Q	==	0x36
_R	==	0x37
_S	==	0x38
_T	==	0x39
_U	==	0x3A
_V	==	0x3B
_W	==	0x3C
_X	==	0x3D
_Y	==	0x3E
_Z	==	0x3F
NL	==	0xC9		; new line
INV	==	0x80		; inversion

	; Values for the character dithered grey mode
GREY_0	==	_I
GREY_1	==	SL
GREY_2	==	_3
GREY_3	==	QM
GREY_4	==	MI
GREY_5	==	_X
GREY_6	==	_J
GREY_7	==	_P
GREY_8	==	_P+INV
GREY_9	==	_J+INV
GREY_A	==	_X+INV
GREY_B	==	MI+INV
GREY_C	==	QM+INV
GREY_D	==	_3+INV
GREY_E	==	SL+INV
GREY_F	==	_I+INV

;= Program code =================================================

	.area	CODE

;- Standard text screen routine ---------------------------------
; This needs text_file and i_reg set to the display to be shown
; and the value of the I register to use, respectively.

show_text::
	.dw	0
st_p_top	=	.
	.db	M_TOP-2
st_p_bottom	=	.
	.db	M_BOTTOM

	ld	a,#394+DELAY_OFFSET
st_s_count	=	.+1
	ld	b,#1
	dec	b
	jr	z,st_delay	; -5
	ld	a,b		; 4
	ld	(st_s_count),a	; 13
	dec	a		; 4

	ld	a,(st_p_top)	; 13
	jr	nz,st_a_change	; 12/7
	jr	st_a_last	; 12
st_a_change:
st_s_top	=	.+1
	add	#0		; 7
st_a_last:
	ld	(st_p_top),a	; 13

	ld	a,(st_p_bottom)	; 13
st_s_bottom	=	.+1
	add	#0		; 7
	ld	(st_p_bottom),a	; 13

	ld	a,(st_p_lines)	; 13
st_s_lines	=	.+1
	add	#0		; 7
	ld	(st_p_lines),a	; 13

	ld	a,(st_p_mask)	; 13
st_s_mask	=	.
	and	a		; 4
	ld	(st_p_mask),a	; 13
	jr	nc,st_a_no_add	; 12/7

	ld	hl,(st_p_offset); 16
st_s_offset	=	.+1
	ld	de,#0		; 10
	add	hl,de		; 11
	ld	(st_p_offset),hl; 16
	jr	st_a_quit	; 12

st_a_no_add:
	ex	(sp),hl		; 19, dummy
	ex	(sp),hl		; 19, dummy
	add	hl,de		; 11, dummy
	add	hl,de		; 11, dummy

st_a_quit:
	ld	a,#394-236+DELAY_OFFSET ; 7
				; = 236
st_delay:
	call	delay

	ld	hl,(text_file)
st_p_offset	=	.+1
	ld	de,#0x8000
	add	hl,de

	ld	a,(i_reg)
	ld	i,a

	ld	de,#TEXT_COLUMNS+1
	ld	ix,#st_back
st_p_lines	=	.+1
	ld	b,#TEXT_ROWS*8
st_p_mask	=	.+1
	ld	a,#1<<7

st_loop:
	push	ix		; 15
	jp	(hl)		; 4
	; line...		; TEXT_COLUMNS*4
	; ret			; 10
st_back:
	ld	c,(hl)		; 7, dummy
	ld	c,c		; 4, dummy
	ld	c,a		; 4, C must be less than 0xFF
	rrca			; 4
	jr	nc,st_no_add	; 12/7

	add	hl,de		; 11
	djnz	st_loop		; 13

	ret

st_no_add:
	inc	bc		; 6, dummy
	djnz	st_loop		; 13

	ret

;- Reset roll mode to full display ------------------------------

	.if	0		; not used  - - - - - - - - - - -

t_reset::
	ld	hl,#tr_table
	jr	set_roll

tr_table:
	.db	1		; for st_s_count
	.db	0		; for st_s_top
	.db	M_TOP-2		; for st_p_top
	.db	0		; for st_s_bottom
	.db	M_BOTTOM	; for st_p_bottom
	.dw	0		; for st_s_offset
	.dw	0x8000		; for st_p_offset
	.db	0		; for st_s_lines
	.db	TEXT_ROWS*8	; for st_p_lines
	and	a		; for st_s_mask
	.db	1<<7		; for st_p_mask

	.endif			; not used  - - - - - - - - - - -

;- Roll text in from the bottom ---------------------------------

t_in_up::
	ld	hl,#tiu_table
	jr	set_roll

tiu_table:
	.db	TEXT_ROWS*8+1		; for st_s_count
	.db	-1			; for st_s_top
	.db	M_TOP-2+TEXT_ROWS*8-1	; for st_p_top
	.db	0			; for st_s_bottom
	.db	M_BOTTOM		; for st_p_bottom
	.dw	-(TEXT_COLUMNS+1)	; for st_s_offset
	.dw	0x8000+TEXT_ROWS*(TEXT_COLUMNS+1)
					; for st_p_offset
	.db	+1			; for st_s_lines
	.db	0			; for st_p_lines
	rlca				; for st_s_mask
	.db	1<<7			; for st_p_mask

;- Roll text out from the bottom --------------------------------

t_out_up::
	ld	hl,#tou_table
	jr	set_roll

tou_table:
	.db	TEXT_ROWS*8+1		; for st_s_count
	.db	0			; for st_s_top
	.db	M_TOP-2			; for st_p_top
	.db	+1			; for st_s_bottom
	.db	M_BOTTOM-1		; for st_p_bottom
	.dw	0			; for st_s_offset
	.dw	0x8000			; for st_p_offset
	.db	-1			; for st_s_lines
	.db	TEXT_ROWS*8+1		; for st_p_lines
	and	a			; for st_s_mask
	.db	1<<7			; for st_p_mask

;- Roll text in from the top ------------------------------------

t_in_down::
	ld	hl,#tid_table
	jr	set_roll

tid_table:
	.db	TEXT_ROWS*8+1		; for st_s_count
	.db	0			; for st_s_top
	.db	M_TOP-2			; for st_p_top
	.db	-1			; for st_s_bottom
	.db	M_BOTTOM+TEXT_ROWS*8	; for st_p_bottom
	.dw	0			; for st_s_offset
	.dw	0x8000			; for st_p_offset
	.db	+1			; for st_s_lines
	.db	0			; for st_p_lines
	and	a			; for st_s_mask
	.db	1<<7			; for st_p_mask

;- Roll text out from the top -----------------------------------

t_out_down::
	ld	hl,#tod_table
	jr	set_roll

tod_table:
	.db	TEXT_ROWS*8+1		; for st_s_count
	.db	+1			; for st_s_top
	.db	M_TOP-2			; for st_p_top
	.db	0			; for st_s_bottom
	.db	M_BOTTOM		; for st_p_bottom
	.dw	+(TEXT_COLUMNS+1)	; for st_s_offset
	.dw	0x8000-(TEXT_COLUMNS+1)	; for st_p_offset
	.db	-1			; for st_s_lines
	.db	TEXT_ROWS*8+1		; for st_p_lines
	rrca				; for st_s_mask
	.db	1<<0			; for st_p_mask

;- Set up roll mode ---------------------------------------------

set_roll:
	push	hl
	call	vsync
	pop	hl

	ld	a,(hl)
	inc	hl
	ld	(st_s_count),a

	ld	a,(hl)
	inc	hl
	ld	(st_s_top),a
	ld	a,(hl)
	inc	hl
	ld	(st_p_top),a

	ld	a,(hl)
	inc	hl
	ld	(st_s_bottom),a
	ld	a,(hl)
	inc	hl
	ld	(st_p_bottom),a

	ld	e,(hl)
	inc	hl
	ld	d,(hl)
	inc	hl
	ld	(st_s_offset),de
	ld	e,(hl)
	inc	hl
	ld	d,(hl)
	inc	hl
	ld	(st_p_offset),de

	ld	a,(hl)
	inc	hl
	ld	(st_s_lines),a
	ld	a,(hl)
	inc	hl
	ld	(st_p_lines),a

	ld	a,(hl)
	inc	hl
	ld	(st_s_mask),a
	ld	a,(hl)
	ld	(st_p_mask),a

	ret

;- Wait for roll mode to finish ---------------------------------

t_ready::
	ld	a,(st_s_count)
	dec	a
	jr	nz,t_ready
	ret

;- Puts a character into a bitmap -------------------------------
; A  character, only non-inverted
; C  width of bitmap in byte
; HL pointer to bitmap

render_char::
	push	bc
	push	de
	push	hl

	.if	CHAR_HEIGHT-8
	.error	"Code depends on CHAR_HEIGHT=8"
	.endif
	ld	d,#ZX_FONT_I_REG>>1
	add	a,a
	add	a,a
	add	a,a
	rl	d
	ld	e,a		; calculate pointer into font

	ld	b,#CHAR_HEIGHT
rc_loop:
	ld	a,(de)
	inc	de
	ld	(hl),a

	ld	a,l
	add	a,c
	ld	l,a
	jr	nc,rc_next
	inc	h
rc_next:
	djnz	rc_loop

	pop	hl
	pop	de
	pop	bc
	ret

;= The end ======================================================
